package com.kpmg.datalake.common.handler;

import com.kpmg.datalake.common.constants.Constants;
import com.kpmg.datalake.common.database.DatabaseTemplate;
import com.kpmg.datalake.common.enums.ExportFormatEnum;
import com.kpmg.datalake.common.enums.ReportTypeEnum;
import com.kpmg.datalake.common.model.DataExportCondition;
import com.kpmg.datalake.common.model.QueryRequestParam;
import com.kpmg.datalake.common.utils.Utils;
import com.kpmg.datalake.db.dao.RqsAccbookMapper;
import com.kpmg.datalake.db.dao.RqsListMapper;
import com.kpmg.datalake.db.model.RqsAccbook;
import com.kpmg.datalake.db.model.RqsList;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.sql.Connection;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
import java.util.Map.Entry;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 查询请求处理
 * @author Tony
 */
public class QueryRequestHandler implements Runnable {

	private static final Logger logger = LoggerFactory.getLogger(QueryRequestHandler.class);

	private QueryRequestParam param;

	public QueryRequestHandler(QueryRequestParam param) {
		this.param = param;
	}

	@Override
	public void run() {
		handleRequest();
	}

	/**
	 * 处理请求
	 */
	public void handleRequest() {
		logger.info("请求处理:{}开始",param.getRequestNo());
        try (Connection conn = param.getDatabase().getConnection()) {
			Map<String, String> bookMap = getRqsAccbook(param.getRequestNo(), param.getRqsAccbookMapper());
			DateFormat dateFormat=new SimpleDateFormat("yyyyMMddHHmmss");
			String personalPath = param.getPersonalPath();
            List<String> fileStoreLocation = exportDataByFormat(conn, param.getCondition(), bookMap, param.getSqlText(), personalPath, param.getRequestNo());
			File dir = new File(personalPath);
			if (!dir.exists()) {
				dir.mkdirs();
			}
			StringBuilder outputZipFileName = new StringBuilder();
			outputZipFileName.append(param.getProject().getEntityBasic().getEntShrtnm());
			String suffix = ".zip";
			DataExportCondition condition=param.getCondition();
            outputZipFileName.append(ReportTypeEnum.getDisplayByCode(condition.getExportType()));
            String format = ExportFormatEnum.getTypeByCode(condition.getExportFormat());
			outputZipFileName.append("(").append(condition.getYear()).append("-").append(Utils.formatMonth(condition.getMonthBegin())).append("-")
					.append(Utils.formatMonth(condition.getMonthEnd())).append(")");
			if (!StringUtils.isEmpty(format)) {
				outputZipFileName.append("_").append(format);
			}
			outputZipFileName.append("(").append(dateFormat.format(new Date())).append(")");
			outputZipFileName.append(suffix);
		
			File outputZipFile=new File(dir,outputZipFileName.toString());
			generateZipFile(fileStoreLocation, outputZipFile);
			
			RqsListMapper rqsListMapper=param.getRqsListMapper();
			RqsList rqsList=new RqsList();
			rqsList.setRqsListId(param.getRequestNo());
			rqsList.setRqsSt("执行完成");
			rqsList.setFilePath(outputZipFile.getAbsolutePath());
			rqsListMapper.updateByPrimaryKeySelective(rqsList);
			
		} catch (Exception e) {
			RqsListMapper rqsListMapper = param.getRqsListMapper();
			RqsList rqsList = new RqsList();
			rqsList.setRqsListId(param.getRequestNo());
			rqsList.setRqsSt("执行失败");
			rqsList.setFilePath("");
			rqsListMapper.updateByPrimaryKeySelective(rqsList);
			logger.error("请求处理:" + param.getRequestNo() + "异常，",e);
		}

		logger.info("请求处理:{}结束",param.getRequestNo());
	}

	private void generateZipFile(List<String> fileStoreLocation, File outputZipFile) {
		try (
				FileOutputStream outputZipStream=new FileOutputStream(outputZipFile);
				ZipOutputStream zipOutputStream = new ZipOutputStream(outputZipStream);
			) {
			
			for (String location : fileStoreLocation) {
				String entryName = location.substring(location.lastIndexOf(File.separator) + 1);
				ZipEntry zipEntry = new ZipEntry(entryName);
				zipOutputStream.putNextEntry(zipEntry);
				
				File entryFile=new File(location);
				FileInputStream fileInputStream = new FileInputStream(entryFile);
				IOUtils.copy(fileInputStream, zipOutputStream);
				fileInputStream.close();
			}
			zipOutputStream.closeEntry();
		} catch (Exception e) {
			logger.error("请求处理:" + param.getRequestNo() + "异常，",e);
		}
	}

	/**
	 * 获取请求账簿信息
	 * @param requestNo
	 * @param rqsAccbookMapper
	 * @return
	 */
	private Map<String, String> getRqsAccbook(String requestNo, RqsAccbookMapper rqsAccbookMapper) {
		Map<String, String> bookMap = new LinkedHashMap<>();
		List<RqsAccbook> accbooks = rqsAccbookMapper.selectByRqsListId(requestNo);
		for (RqsAccbook book : accbooks) {
			bookMap.put(book.getAccbookCd(), book.getAccbookCd() + "_" + book.getAccbookNm());
		}
		return bookMap;
	}

	/**
	 * 按导出格式导出数据
     *
     * @param connection connection
     * @param condition condition
     * @param bookMap bookMap
     * @param sqlText sqlText
     * @return List
     * @throws Exception Exception
	 */
	private List<String> exportDataByFormat(Connection connection, DataExportCondition condition,
                                            Map<String, String> bookMap, String sqlText, String personalPath, String requestNo) {

		List<String> fileStoreLocations = new LinkedList<>();
		String exportFormat = condition.getExportFormat();

		if (ExportFormatEnum.EXPORT_FORMAT_PER_BOOK.getCode().equals(exportFormat)) {
			// 按账套以及账目种类生成文件，查询结果按账套以及种类保存至map
			exportPerBook(connection, condition, bookMap, personalPath, fileStoreLocations,
                    sqlText);
        } else if (ExportFormatEnum.EXPORT_FORMAT_PER_MONTH.getCode().equals(exportFormat)) {
			// 按账目种类月生成文件，查询结果按账目种类以及月份保存至map
			exportPerMonth(connection, condition, personalPath, requestNo, fileStoreLocations,
                    sqlText);
        } else if (ExportFormatEnum.EXPORT_FORMAT_SINGLE_FILE.getCode().equals(exportFormat)) {
			// 导出单个文件
			exportSingleFile(connection, condition, personalPath, requestNo, fileStoreLocations,
                    sqlText);
		}
		return fileStoreLocations;
	}
	
	private String yearStr="\\#\\{year}";
	private String beginMonthStr="\\#\\{begin_month}";
	private String endMonthStr="\\#\\{end_month}";
	
	private void exportSingleFile(Connection connection, DataExportCondition condition,
			String personalPath, String requestNo, List<String> fileStoreLocations,
			String dataQuerySql) {
		LocalDateTime start;
		

		logger.info("{}","导出单文件");
		start = LocalDateTime.now();
		
		String key = Constants.FILE_NAME_PREFIX + "(" + condition.getYear() + "-"
				+ Utils.formatMonth(condition.getMonthBegin()) + "-" + Utils.formatMonth(condition.getMonthEnd())
				+ ")";
		String savePath=getDataStorePath(key, condition, personalPath);
		
		String querySql = dataQuerySql==null?dataQuerySql:dataQuerySql.replaceAll(yearStr, "'"+condition.getYear()+"'")
				.replaceAll(beginMonthStr, "'"+Utils.formatMonth(condition.getMonthBegin())+"'")
				.replaceAll(endMonthStr, "'"+Utils.formatMonth(condition.getMonthEnd())+"'")
				.replaceAll("\\#\\{RQS_LIST_ID}", requestNo).replaceAll(";", "");
		fileStoreLocations.add(DatabaseTemplate.queryForData(savePath, querySql, connection));

		logger.info("导出单文件，耗时：{}ms", Duration.between(start, LocalDateTime.now()).toMillis());
	}

	private void exportPerMonth(Connection connection, DataExportCondition condition,
			String personalPath, String requestNo, List<String> fileStoreLocations,
			String dataQuerySql) {
		LocalDateTime start;

		for(String month:param.getCondition().getMonthList()) {
			logger.info("查询月份对应数据信息，月份：{}", month);
			start = LocalDateTime.now();
			
			String key = Constants.FILE_NAME_PREFIX + "(" + condition.getYear() + "-"
					+ Utils.formatMonth(String.valueOf(month)) + "-" + Utils.formatMonth(String.valueOf(month))
					+ ")" + "_按月";
			String savePath=getDataStorePath(key, condition, personalPath);
			
			String querySql = dataQuerySql==null?dataQuerySql:dataQuerySql.replaceAll(yearStr, "'"+condition.getYear()+"'")
					.replaceAll(beginMonthStr, "'"+Utils.formatMonth(String.valueOf(month))+"'")
					.replaceAll(endMonthStr, "'"+Utils.formatMonth(String.valueOf(month))+"'")
					.replaceAll("\\#\\{month}", "'"+Utils.formatMonth(String.valueOf(month))+"'")
					.replaceAll("\\#\\{RQS_LIST_ID}", requestNo).replaceAll(";", "");
			fileStoreLocations.add(DatabaseTemplate.queryForData(savePath, querySql, connection));
			
			logger.info("查询账套对应月份{}数据信息，耗时：{}ms", month, Duration.between(start, LocalDateTime.now()).toMillis());
		}
	}

	private void exportPerBook(Connection connection, DataExportCondition condition, Map<String, String> bookMap,
			String personalPath, List<String> fileStoreLocations,String dataQuerySql) {
		LocalDateTime start;

		for (Entry<String, String> entry : bookMap.entrySet()) {
			String bookName = entry.getValue();
			logger.info("查询账套对应数据信息，账套：{}", bookName);
			start = LocalDateTime.now();
			
			String key = Constants.FILE_NAME_PREFIX + bookName;
			String savePath=getDataStorePath(key, condition, personalPath);

			String querySql = dataQuerySql==null?dataQuerySql:dataQuerySql.replaceAll(yearStr, "'"+condition.getYear()+"'")
					.replaceAll(beginMonthStr, "'"+Utils.formatMonth(condition.getMonthBegin())+"'")
					.replaceAll(endMonthStr, "'"+Utils.formatMonth(condition.getMonthEnd())+"'")
					.replaceAll("\\#\\{actbk_cd}", "'"+entry.getKey()+"'")
					.replaceAll("\\#\\{book_id}", entry.getKey()).replaceAll(";", "");
			fileStoreLocations.add(DatabaseTemplate.queryForData(savePath, querySql, connection));
			
			logger.info("查询账套对应数据信息，耗时：{}ms", Duration.between(start, LocalDateTime.now()).toMillis());
		}
	}

    /**
     * 保存数据文件信息
     *
     * @param bookPk
     * @param condition
     * @param personalPath
     * @return
     */
	private String getDataStorePath(String bookPk, DataExportCondition condition, String personalPath)
			 {
		// 获取导出类型
		String exportType = condition.getExportType();
		StringBuilder fileNamePrefix = new StringBuilder();
		String suffix = ".csv";
		String exportFormat = condition.getExportFormat();

                 fileNamePrefix.append(ReportTypeEnum.getDisplayByCode(exportType));
                 if (ExportFormatEnum.EXPORT_FORMAT_PER_BOOK.getCode().equals(exportFormat)) {
			// 一个账套一个文件
			fileNamePrefix.append("(").append(condition.getYear()).append("-")
					.append(Utils.formatMonth(condition.getMonthBegin())).append("-")
					.append(Utils.formatMonth(condition.getMonthEnd())).append(")").append("_");
		} else {
			suffix = ".txt";
		} 
		return personalPath + File.separator
				+ bookPk.replace(Constants.FILE_NAME_PREFIX, fileNamePrefix).replace("\\", "").replace("/", "")
				.replace(":", "").replace("*", "").replace("?", "").replace("\"", "").replace("<", "")
				.replace(">", "").replace("|", "").replace("“", "").replace("”", "")+ suffix;
	}
	

}
